/*************************************************
 * HISTORY:                                      *
 *	06/22/2020 pyx : Created.                    *
 *	06/01/2022 pyx : Edited.                     *
=================================================*/

#include "DATransformerSymbolTable.h"

SymbolTable::Symbol *SymbolTable::getSymbol(unsigned sid)
{
    assert(sid <= m_st.size());

    return m_st[sid - 1]; // index = sid-1
}

unsigned SymbolTable::getsid(std::string signature, SymbolType st, std::string name)
{
    std::cout << "in getsid:" << signature << "|" << std::endl;
    int nums = symbolIDTable.count(signature);
    std::cout << "nums=" << nums << std::endl;
    assert(nums <= 1);
    if (nums == 1)
    {
        unsigned sid = symbolIDTable[signature];

        Symbol *ts = getSymbol(sid);

        trim(name);
        trim(ts->name);

        if (name != ts->name)
        {
            if (name.empty() && ts->name.empty())
            {
            }
            else if (name.empty())
            {
            }
            else if (ts->name.empty())
            {
                ts->name = name;
            }
            else
            {

                std::cout << "INTERNAL ERROR!\n same symbol sig has different names:\nsig:" << signature << "\n1):" << name << " \n2):" << ts->name << "\n";
                exit(1);
            }
        }

        if (st != ts->st)
        {

            if (st != ST_Max && ts->st != ST_Max)
            {
                // FIXME
                // TODO
                std::cout << "INTERNAL ERROR!\n same symbol sig has different types:\nsig:" << signature << "\n1):" << st << " \n2):" << ts->st << "\n";
                // exit(1);
            }
            else if (ts->st == ST_Max)
            {
                ts->st = st;
            }

            // if(symbolTable[sid]->st == ST_Max) symbolTable[sid]->st = st;
        }
        return sid;
    }
    else
    {
        return insertSymbol(signature, st, name);
    }
}

unsigned SymbolTable::insertSymbol(std::string signature, SymbolType st, std::string name)
{
    assert(st >= 0 && st <= ST_Max); // FIXME
    assert(!signature.empty());
    // assert(!name.empty());

    Symbol *s = new Symbol;

    s->signature = signature;
    s->st = st;
    s->name = name;

    m_st.push_back(s);
    unsigned newsid = m_st.size();
    symbolIDTable[signature] = newsid;

    return newsid;
}

void SymbolTable::insertDef(unsigned sid, unsigned fid, RefType rt, std::string location)
{
    assert(rt >= 0 && rt < RT_Max); // FIXME
    assert(fid > 0);
    assert(sid > 0);

    Ref *r = new Ref;

    r->sid = sid;
    r->fid = fid;
    r->rt = rt;
    r->loc = location;
    r->refid = currRefid++;

    globalDefTable.push_back(r);
}
void SymbolTable::insertDec(unsigned sid, unsigned fid, RefType rt, std::string location)
{
    assert(rt >= 0 && rt < RT_Max); // FIXME
    assert(fid > 0);
    assert(sid > 0);

    Ref *r = new Ref;

    r->sid = sid;
    r->fid = fid;
    r->rt = rt;
    r->loc = location;
    r->refid = currRefid++;

    globalDecTable.push_back(r);

    // std::cout<<"insert ok @"<<s->name <<"|"<< s->loc<<"|"<<std::endl;
}

void SymbolTable::insertRef(unsigned sid, unsigned fid, RefType rt, std::string location)
{
    assert(rt >= 0 && rt < RT_Max); // FIXME
    assert(fid > 0);
    assert(sid > 0);

    Ref *r = new Ref;

    r->sid = sid;
    r->fid = fid;
    r->rt = rt;
    r->loc = location;
    r->refid = currRefid++;

    refTable.push_back(r);
}

void SymbolTable::insertSymbolDep(unsigned ssid, unsigned sfid, unsigned esid, std::string efilepath, SDependencyType sdt)
{
    assert(sdt >= 0 && sdt < SDT_Max); // FIXME
    assert(ssid > 0);
    assert(sfid > 0);
    assert(esid > 0);
    assert(efilepath.size() > 0);

    SDep *sd = new SDep;

    sd->ssid = ssid;
    sd->sfid = sfid;
    sd->esid = esid;
    sd->efilepath = efilepath;
    sd->sdt = sdt;

    symbolDepTable.push_back(sd);
}

void SymbolTable::mappingSymbolDep(std::map<std::pair<unsigned, unsigned>, unsigned> &sidMap)
{
    int n = symbolDepTable.size();
    if (sdepsidx == n)
    {
        return;
    }
    if (sdepsidx > n)
    {
        std::cout << "INTERNAL ERROR! sdepidx>n!" << sdepsidx << ">" << n << std::endl;
        exit(1);
    }

    for (int i = sdepsidx; i < n; ++i)
    {
        SDep *iter = symbolDepTable[i];

        std::pair<unsigned, unsigned> keys = std::make_pair(iter->sfid, iter->ssid);
        if (sidMap.find(keys) == sidMap.end())
        {
            std::cout << "INTERNAL ERROR! can't find start sid mapping!" << iter->sfid << "," << iter->ssid << std::endl;
            exit(1);
        }
        iter->ssid = sidMap[keys];

        unsigned efid = m_fm->getFID_not_add(iter->efilepath);

        keys = std::make_pair(efid, iter->esid);
        if (sidMap.find(keys) == sidMap.end())
        {
            std::cout << "INTERNAL ERROR! can't find end sid mapping!" << efid << "@ori path:@" << iter->efilepath << "@fm:@" << m_fm->getFilePath(efid) << "," << iter->esid << std::endl;
            std::cout << iter->sfid << "@sf path:@" << m_fm->getFilePath(iter->sfid) << "," << iter->ssid << std::endl;

            exit(1);
        }
        iter->esid = sidMap[keys];

        assert(iter->ssid > 0);
        assert(iter->esid > 0);
    }

    sdepsidx = n;
}

SymbolTable::SymbolTable(FileManager *fm)
{
    this->m_fm = fm;
}

SymbolTable::~SymbolTable()
{

    for (Symbol *sym : m_st)
        delete sym;
    for (Ref *ref : globalDefTable)
        delete ref;
    for (Ref *ref : globalDecTable)
        delete ref;
}

void SymbolTable::finilize()
{
    Connector *c = new Connector();
    std::cout << "ok st conn" << std::endl;

    int n;

    n = m_st.size();

    std::cout << "symboltable size=" << n << std::endl;

    for (int i = 0; i < n; i++)
    {
        Symbol *iter = m_st[i];

        c->insertSymbol(i + 1, iter->signature, (int)iter->st, iter->name); // sid = index+1
    }

    c->commit();

    n = globalDefTable.size();

    for (int i = 0; i < n; i++)
    {
        Ref *iter = globalDefTable[i];

        c->insertDef(iter->refid, iter->sid, iter->fid, (int)iter->rt, iter->loc);
    }

    c->commit();

    n = globalDecTable.size();

    for (int i = 0; i < n; i++)
    {
        Ref *iter = globalDecTable[i];

        c->insertDec(iter->refid, iter->sid, iter->fid, (int)iter->rt, iter->loc);
    }

    c->commit();

    n = refTable.size();

    for (int i = 0; i < n; i++)
    {
        Ref *iter = refTable[i];

        c->insertRef(iter->refid, iter->sid, iter->fid, (int)iter->rt, iter->loc);
    }

    c->commit();

    n = symbolDepTable.size();

    std::cout << "n=" << n << "\n";

    for (int i = 0; i < n; i++)
    {
        SDep *iter = symbolDepTable[i];

        c->insertSymbolDep(i + 1, iter->ssid, iter->esid, (int)iter->sdt); // sdepid starts from 1
    }

    c->commit();

    delete c;
}